using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;
using System.IO;

namespace Hack.DllDump
{
    public class Method : IComparable
    {
        protected System.Reflection.MethodInfo info;

        public Method(MethodInfo info)
        {
            this.info = info;

        }
        /*
         * Get the MSIL code in this method
         */
        public ArrayList MSILCode() 
        {
            ArrayList ildata = new ArrayList();
            /*
             * Get the method data
             */
            MethodBody mb = info.GetMethodBody();
            if (mb != null)
            {
                byte[] il = mb.GetILAsByteArray();
                if (il != null)
                {
                    int inslength;
                    for (int currentpos = 0;
                        currentpos < il.Length; 
                        currentpos += inslength) 
                    {
                        /*
                         * Get the string version of the instruction and the length,
                         * including any operand
                         */
                        inslength = 0;
                        string name = Disassembler.Decode(il, currentpos, out inslength);
                        /*
                         * Format this and add to the list
                         */
                        ildata.Add(String.Format("{0:X8}: {1}", currentpos,name));

                    }
                    
                }
            }
            // return list of instructions

            return ildata;
        }

        public void ToString(StringWriter sw)
        {
            ToString(sw, false);
        }

        public void ToString(StringWriter sw, bool ShowCode)
        {
            if (info != null)
            {
                ParameterList pw = new ParameterList(info.GetParameters());
                /*
                 * Get length of generated code
                 */
                int codelength = 0;
                MethodBody mb = info.GetMethodBody();
                if (mb != null)
                {
                    byte[] il = mb.GetILAsByteArray();
                    if (il != null)
                    {
                        codelength = il.Length;
                    }
                }

                sw.WriteLine("{0}{1}{2}{3} {4} {5} ",
                    info.IsPrivate ? " private " : "",
                    info.IsPublic ? " public " : "",
                    info.IsStatic ? " static " : "",
                    info.IsVirtual ? " virtual " : "",
                    info.ReturnType.Name,
                    info.Name);
                /*
                 * Load and Display parameters
                 */
                sw.Write("\t");
                pw.ToString(sw);
                sw.WriteLine("");

                if (ShowCode)
                {
                    sw.WriteLine("\t{0} Bytes of code", codelength);
                    ArrayList ilcode = MSILCode();
                    foreach (string s in ilcode)
                    {
                        sw.WriteLine("\t{0}", s);
                    }
                }
                else
                {
                    sw.Write("\t{//");
                    sw.Write("{0} Bytes of code", codelength);
                    sw.Write("}");
                }
            }
        }
    

        /* 
         * Allow these to be sorted by name
         */
        public int CompareTo(object o)
        {
            Method target = (Method)o;
            return info.Name.CompareTo(target.info.Name);
        }
    }
}
